package cc.rboot.feature.aspect;

import cc.rboot._core.helper.AnnotationHelper;
import cc.rboot._core.holder.AppContextHolder;
import cc.rboot.feature.annotation.Feature;
import cc.rboot.feature.core.IFeatureResolver;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

// 同一个特性的各个条件必须互斥，否则会造成选错分支代码的问题
// FeatureMethodEnum = > < >= <= in not_in
// 目前支持 TimeFeatureResolver
// 未来支持 productionVersion version time os token
//// 产品版本 productionVersion
//// 前端版本 version < 1.0.1
// 前端OS os = mini、os = ios、 os = android、 os = pc
// token token = agent、 token = staff、 token = none
@Aspect
@Component
public class FeatureAspect {

    @Pointcut("@annotation(cc.rboot.feature.annotation.Feature)")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Feature currentFeature = AnnotationHelper.get(joinPoint, Feature.class);

        String name = currentFeature.name();

        Method sureMethod = null;

        for (Method method : joinPoint.getTarget().getClass().getMethods()) {
            if (method.isAnnotationPresent(Feature.class)) {
                Feature featureOfMethod = method.getAnnotation(Feature.class);
                if (name.equals(featureOfMethod.name())) {
                    Class<? extends IFeatureResolver> processorClass = featureOfMethod.resolver();
                    IFeatureResolver basicFeatureProcessor =  AppContextHolder.getBean(processorClass);
                    if (basicFeatureProcessor.check(featureOfMethod.method(), featureOfMethod.conditions())) {
                        if (sureMethod != null) {
                            throw new Exception("特性" + name + "条件不互斥，无法选定特性执行，请检查代码");
                        }
                        sureMethod = method;
                    }
                }
            }
        }
        if (sureMethod == null) {
            return joinPoint.proceed();
        }

        return sureMethod.invoke(joinPoint.getTarget(), joinPoint.getArgs());
    }

}
